<?php
class commonMod {
	protected $model = NULL; // 数据库模型
	protected $layout = NULL; // 布局视图
	protected $config = array ();
	private $_data = array ();
	protected $mac_sign = NULL;
	protected $openid = NULL;
	protected $did = 0;
	protected $requestNo = 0;
	protected $uid = null;
	protected $shardId = null;
	protected $jsonData = null;
	protected $playerData = null;
	protected $Player = null;
	protected $globalPlayerData = null;
	protected $isTestUser = false;
	protected $device_type = null;
	const JSON_BOOL_MODE = true; /* =true:boolean型を引用符で括る、=false:括らない */
	protected function init() {
		//测试
	}
	public function __construct() {
		global $config;
		$this->config = $config;
		define ( "WEB_URL_SYSTEM", $this->config ['WEB_URL_SYSTEM'] );
		$this->model = self::initModel ( $this->config );
		$this->init ();
// 		if ($_GET['_module'] =='upload'){
// 			return ;
// 		}
		//
		// define ( "API_TIME_MARGIN", "10" );
		// define ( "APP_TOKEN_SEED", "I9singeHk13xqbkc" );
		// define ( "SECRET_KEY", "9ed57f55a59a27349bc6397f89f1bad3" );
		// define ( "CRYPT_LV", "AES" );
		$sec = new SecurityUtil ();
		
		if (! self::isPost ()) {
			$data = self::getErrorNode ( 0, 0, $sec, null, $_GET ['_action'], "POST以外でのアクセス" );
			$data_return = $this->JSON ( $data );
			die ( $data_return );
			exit ();
		}
		
		if ($_POST ['id'] && $_POST ['iv']) {
			$this->uid = $sec->getUserId ( $_POST ['id'], $_POST ['iv'] );
			$user = $this->model->table ( 'users' )->where ( "id =" . $this->uid )->find ();
			if (empty ( $user )) {
				$data = self::getErrorNode ( 0, 0, $sec, null, $_GET ['_action'], "用户不存在" );
				$data_return = $this->JSON ( $data );
				die ( $data_return );
				exit ();
			} else {
				$this->user = $user;
			}
		} else if ($_POST ['did'] && $_POST ['iv']) { // did認証
			$this->did = $sec->getDid ( $_POST ["did"], $_POST ["iv"] );
		}
		$this->device_type = $_POST['device_type'];
		if ($_POST['data']){
			$jsonData = $sec->getDecryptData ( $_POST['data'], $_POST ["iv"] );
			$jsonData = json_decode ( $jsonData, true );
			
			if ($jsonData === null) {
				$explanation = "リクエストJSONのデコードに失敗しました。";
				$response = $this->returnAsError ( 201, $explanation,$_GET['_action']);
				$data_return = $this->JSON ( (array)$response );
				die ( $data_return );
				exit ();
				return;
			} else if (! array_key_exists ( $_GET['_action'], $jsonData )) {
				$explanation = "コントローラー名が正しくありません。";
				$response = $this->returnAsError ( 201, $explanation,$_GET['_action']);
				$data_return = $this->JSON ( (array)$response );
				die ( $data_return );
				exit ();
				return;
			}
			
		}
		$jsonDataInner = $jsonData [$_GET['_action']];
		$this->jsonData = $jsonDataInner;
		
	}
	
	protected function returnAsError($errorCode, $explanation,$actionname) {
		if (is_array ( $explanation )) {
			// 必要に応じて最適な形に変換
			$explanation = $this->flattenValidationErrorForApi ( $explanation );
		}
		
		$data = $this->getErrorNode ( $this->did, 0, null, $errorCode, $actionname, $explanation );
		// $this->log($explanation, 'error');
		// Return data as json
// 		$response = new CakeResponse ( array (
// 				'body' => json_encode ( $data ) 
// 		) );
		return $data;
	}
	protected function flattenValidationErrorForApi($error) {
		if (empty ( $error )) {
			return "";
		}
		
		if (is_array ( $error ) && Hash::check ( $error, '{s}.{n}' )) {
			$messageArray = Hash::extract ( $error, '{s}.{n}' );
			return Hash::flatten ( $messageArray );
		} elseif (is_array ( $error )) {
			return Hash::flatten ( $error );
		} else {
			return $error;
		}
	}
	
	// 初始化模型
	static public function initModel($config) {
		static $model = NULL;
		if (empty ( $model )) {
			$model = new cpModel ( $config );
		}
		return $model;
	}
	public function __get($name) {
		return isset ( $this->_data [$name] ) ? $this->_data [$name] : NULL;
	}
	public function __set($name, $value) {
		$this->_data [$name] = $value;
	}
	
	// 获取模板对象
	public function view() {
		static $view = NULL;
		if (empty ( $view )) {
			$view = new cpTemplate ( $this->config );
		}
		return $view;
	}
	
	// 模板赋值
	protected function assign($name, $value) {
		return $this->view ()->assign ( $name, $value );
	}
	
	// 模板显示
	protected function display($tpl = '', $return = false, $is_tpl = true) {
		if ($is_tpl) {
			$tpl = empty ( $tpl ) ? $_GET ['_module'] . '_' . $_GET ['_action'] : $tpl;
			if ($is_tpl && $this->layout) {
				$this->__template_file = $tpl;
				$tpl = $this->layout;
			}
		}
		$this->view ()->assign ( $this->_data );
		return $this->view ()->display ( $tpl, $return, $is_tpl );
	}
	protected function respondSuccess($data = null, $actionname) {
		$encflg = true;
		$jsonData = $this->formatSuccessResponseJsonArray ( $data, $actionname );
		if (empty($this->did)){
			$this->did = 0;
		}
		$body = $this->getNode ( $this->did, 0, new SecurityUtil (), $jsonData, $actionname, $encflg );
		$data_return = $this->JSON ( $body );
		die ( $data_return );
		exit ();
	}
	protected function formatSuccessResponseJsonArray($data = null, $actionname) {
		if ($data != null) {
			return array (
					$actionname => array (
							'result' => true,
							'data' => $data 
					) 
			);
		} else {
			return array (
					$actionname => array (
							'result' => true ,
							'data' => ''
					) 
			);
		}
	}
	
	// 判断是否是数据提交
	protected function isPost() {
		return $_SERVER ['REQUEST_METHOD'] == 'POST';
	}
	
	// 直接跳转
	protected function redirect($url, $code = 302) {
		header ( 'location:' . $url, true, $code );
		exit ();
	}
	
	// 弹出信息
	protected function alert($msg, $url = NULL) {
		header ( "Content-type: text/html; charset=utf-8" );
		$alert_msg = "alert('$msg');";
		if (empty ( $url )) {
			$gourl = 'history.go(-1);';
		} else {
			$gourl = "window.location.href = '{$url}'";
		}
		echo "<script>$alert_msg $gourl</script>";
		exit ();
	}
	
	/**
	 * ************************************************************
	 *
	 * 使用特定function对数组中所有元素做处理
	 *
	 * @param
	 *        	string &$array 要处理的字符串
	 * @param string $function
	 *        	要执行的函数
	 * @return boolean $apply_to_keys_also 是否也应用到key上
	 * @access public
	 *        
	 *         ***********************************************************
	 */
	protected function arrayRecursive(&$array, $function, $apply_to_keys_also = false) {
		static $recursive_counter = 0;
		if (++ $recursive_counter > 1000) {
			die ( 'possible deep recursion attack' );
		}
		foreach ( $array as $key => $value ) {
			if (is_array ( $value )) {
				self::arrayRecursive ( $array [$key], $function, $apply_to_keys_also );
			} else {
				if (strstr ( $value, "\n" )) {
					$value = str_replace ( "\n", "\\n", $value );
				}
				
				if (strstr ( $value, "\"" )) {
					$value = str_replace ( "\"", "\\\"", $value );
				}
				
				// var_dump($value)."<br>";
				$array [$key] = $function ( $value );
			}
			if ($apply_to_keys_also && is_string ( $key )) {
				$new_key = $function ( $key );
				if ($new_key != $key) {
					$array [$new_key] = $array [$key];
					unset ( $array [$key] );
				}
			}
		}
		$recursive_counter --;
	}
	
	/**
	 * ************************************************************
	 *
	 * 将数组转换为JSON字符串（兼容中文）
	 *
	 * @param array $array
	 *        	要转换的数组
	 * @return string 转换得到的json字符串
	 * @access public
	 *        
	 *         ***********************************************************
	 */
	protected function JSON($array) {
		/*
		 * echo "<pre>";
		 * print_r($array);
		 * echo "</pre>";exit;
		 */
		self::arrayRecursive ( $array, 'urlencode', true );
		$json = json_encode ( $array );
		return urldecode ( $json );
	}
	protected function check_user_auth($openid, $mac) {
		$user_info = $this->model->table ( "member" )->where ( " md5(id) = '" . $openid . "' " )->find ();
		if ($mac != $user_info ['mac']) {
			$data_return_array ['result'] = "911";
			$data_return_array ['msg'] = "";
			$data_return_array ['data'] = "";
			
			$data_return = self::JSON ( $data_return_array );
			die ( $data_return );
			exit ();
		}
	}
	public function check_token($token) {
		$user_info = $this->model->table ( "member" )->where ( " user_token = '" . $token . "' " )->find ();
		if (! $user_info) {
			$data_return_array ['result'] = "0";
			$data_return_array ['msg'] = "Hack Error!";
			$data_return_array ['data'] = "";
			
			$data_return = $this->JSON ( $data_return_array );
			die ( $data_return );
			exit ();
		} else {
			$_SESSION ['uuser'] = $user_info;
		}
	}
	public function UserIDIn($actionname) {
		if (! isset ( $_POST ['id'] ) || empty ( $_POST ['id'] )) {
			$this->_msg .= 'post parameter "id" not found.';
			return false;
		}
		
		// ivの有無チェック
		if (! isset ( $_POST ['iv'] ) || empty ( $_POST ['iv'] )) {
			$this->_msg .= 'post parameter "iv" not found.';
			return false;
		}
		
		if (! isset ( $_POST ['datetime'] ) || empty ( $_POST ['datetime'] )) {
			$this->_msg .= 'post parameter "datetime" not found.';
			return false;
		}
		
		// アプリ送出時刻は、許容範囲オーバーか？
		if (! $sec->validateTime ( $_POST ['datetime'] )) {
			// $this->_msg .= 'datetime validation failed.';
			return false;
		}
		
		// トークンはあるか？
		if (! isset ( $_POST ['token'] ) || empty ( $_POST ['token'] )) {
			$this->_msg .= 'post parameter "token" not found.';
			return false;
		}
		
		// トークンは不正か？
		if (! $this->validateToken ( $_POST ['token'], $this->uid, $this->user ['install_key'], $_POST ['datetime'] )) {
			// $this->_msg .= 'invalid token.';
			return false;
		}
	}
	public function DIDOUT($data, $method) {
		$return = array ();
		$return ['error'] = $error;
		$return ['method'] = $method;
		$return ['iv'] = '';
		// $return ['token'] = module("SecurityUtil")->
		$return ['datetime'] = date ( "YmdHis" );
		$return ['request_no'] = 0;
		$return ['data'] = $data;
		return $return;
	}
	public function DIDIN($actionname) {
		$sec = new SecurityUtil ();
		if (! isset ( $_POST ['did'] ) || empty ( $_POST ['did'] )) {
			$this->_msg .= 'Parameter did not found[1].';
			return false;
		}
		if (! isset ( $_POST ['iv'] ) || empty ( $_POST ['iv'] )) {
			$this->_msg .= 'Parameter iv not found.';
			return false;
		}
		
		// 復号化された端末固有ID（did）の取得
		$did = $sec->getDid ( $_POST ['did'], $_POST ['iv'] );
		
		// didの復号化失敗か？
		if (! $did) {
			$this->_msg .= 'Parameter did not found[2].';
			return false;
		}
		
		if (! isset ( $_POST ['datetime'] ) || empty ( $_POST ['datetime'] )) {
			$this->_msg .= 'Parameter datetime not found.';
			return false;
		}
		
		// アプリ送出時刻は、許容範囲オーバーか？
		if (! $sec->validateTime ( $_POST ['datetime'] )) {
			// $this->_msg .= 'Parameter datetime validation failed.';
			return false;
		}
		
		if (! isset ( $_POST ['token'] ) || empty ( $_POST ['token'] )) {
			$this->_msg .= 'Parameter token not found.';
			return false;
		}
		
		if (! $sec->validateTokenInitial ( $_POST ['token'], $did, $_POST ['datetime'] )) {
			$this->_msg .= 'Parameter invalid token.';
			return false;
		}
		
		$post = $_POST;
		unset ( $_POST );
		$_POST = $post ['data'];
		return true;
	}
	
	protected function respondError($errorCode, $errorMessage, $actionname) {
		$data = $this->getErrorNode ( null, 0, null, $errorCode, $actionname, $errorMessage );
		
		$jsonText = json_encode ( $data );
		$data_return = $this->JSON ( $jsonText );
		die ( $data_return );
		exit ();
	}
	
    protected function getErrorNode($did = null, $request_no = 0, $sec = null, $errorCode = 201, $action = null, $message = null) {
		if (empty ( $sec )) {
			$sec = new SecurityUtil ();
		}
		$datetime = date ( 'YmdHis' );
		if (! $action) { // API名なしか？
			$message = "CODE=:JsonManager:action not specified.";
		}
		if ($this->uid && empty ( $did )) {
			$token = $sec->getToken ( $did, $datetime ); // 受信用トークン
		} else {
			$token = $sec->getReceiveToken ( $did, $datetime ); // 受信用トークン
		}
		// パラメータセット
		$params = array (
				'error' => array (
						'code' => $errorCode,
						'message' => $message 
				),
				'method' => $action,
				'iv' => null,
				'token' => $token, // 受信用トークン
				'datetime' => $datetime,
				'request_no' => $request_no 
		); // リクエストNo
		
		return $params;
	}
	
	/**
	 * 正常時のJSON用配列取得
	 *
	 * @param $did 端末固有ID        	
	 * @param $request_no リクエストNo.        	
	 * @param $sec Securityオブジェクト        	
	 * @param $resultArray 返信データの配列        	
	 * @param $action API名        	
	 * @param $encflg true：暗号化あり、false：暗号化なし        	
	 * @return JSON用配列
	 */
	protected function getNode($did, $request_no, $sec = null, $resultArray = null, $action = null, $encflg = true) {
		if (empty ( $sec )) {
			$sec = new SecurityUtil ();
		}
		$datetime = date ( 'YmdHis' );
		
		if (! $action) { // API名なしか？
			$msg = "action not specified.";
			return self::getErrorNode ( $sec, null, null, $msg );
		}
		
		if (self::JSON_BOOL_MODE) {
			self::setQuotation ( $resultArray );
			$nullData = "null";
		} else {
			$nullData = null;
		}
		
		$jsonText = json_encode ( $resultArray );
		$iv = "";
		
		if ($encflg) { // 暗号化ありか？
			$ret = $sec->encrypt ( $jsonText );
			// iv、resultを算出
			if (isset ( $ret ['hex_enc_str'] ) && isset ( $ret ['hex_iv_str'] )) {
				$jsonText = $ret ['hex_enc_str'];
				$iv = $ret ['hex_iv_str'];
			} else {
				$msg = "hex_enc_str or hex_iv_str not found.";
				return self::getErrorNode ( $sec, null, null, $msg );
			}
		}
		
		// if (API_COMPRESS) {
		// $jsonText = gzcompress ( $jsonText );
		// $jsonText = base64_encode ( $jsonText );
		// }
		if ($this->uid && empty ( $did )) {
			$token = $sec->getToken ( $did, $datetime ); // 受信用トークン
		} else {
			$token = $sec->getReceiveToken ( $did, $datetime ); // 受信用トークン
		}
		// パラメータセット
		$params = array (
				'error' => $nullData,
				'method' => $action,
				'iv' => $iv,
				'token' => $token,
				'datetime' => $datetime,
				'request_no' => $request_no, // リクエストNo
				'data' => $jsonText 
		);
		
		return $params;
	}
	
	/**
	 * 連想配列の値を文字列変換する（ダブルクォーテーションで括る）
	 *
	 * @param
	 *        	array &$para 変換する文字
	 */
	protected function setQuotation(array &$para) {
		foreach ( $para as $key => &$val ) {
			
			if (is_array ( $val )) {
				self::setQuotation ( $val );
			} else {
				if (is_bool ( $val )) { // boolean型か？
					if ($val) {
						$para [$key] = "true";
					} else {
						$para [$key] = "false";
					}
				} else if (is_null ( $val )) { // NULLか？
					$para [$key] = "null";
				} else {
					$para [$key] = strval ( $val ); // 文字に変換
				}
			}
		}
		return;
	}
	public function i_array_column($input, $columnKey, $indexKey = null) {
		if (! function_exists ( 'array_column' )) {
			$columnKeyIsNumber = (is_numeric ( $columnKey )) ? true : false;
			$indexKeyIsNull = (is_null ( $indexKey )) ? true : false;
			$indexKeyIsNumber = (is_numeric ( $indexKey )) ? true : false;
			$result = array ();
			foreach ( ( array ) $input as $key => $row ) {
				if ($columnKeyIsNumber) {
					$tmp = array_slice ( $row, $columnKey, 1 );
					$tmp = (is_array ( $tmp ) && ! empty ( $tmp )) ? current ( $tmp ) : null;
				} else {
					$tmp = isset ( $row [$columnKey] ) ? $row [$columnKey] : null;
				}
				if (! $indexKeyIsNull) {
					if ($indexKeyIsNumber) {
						$key = array_slice ( $row, $indexKey, 1 );
						$key = (is_array ( $key ) && ! empty ( $key )) ? current ( $key ) : null;
						$key = is_null ( $key ) ? 0 : $key;
					} else {
						$key = isset ( $row [$indexKey] ) ? $row [$indexKey] : 0;
					}
				}
				$result [$key] = $tmp;
			}
			return $result;
		} else {
			return array_column ( $input, $columnKey, $indexKey );
		}
	}


	//100
	//通知详情
	public function get_notice() {
		$info = $this->model->table('gossip_news')->where(" id = ".$this->jsonData['id'])->find();
		$info['text']=$info['message'];
		$info['date']=$info['created'];
		unset($info['message']);
		unset($info['created']);
		unset($info['user_id']);
		unset($info['modified']);
		$data['result']=true;
		$data['data']=$info;
		$this->respondSuccess($data,$_GET['_action']);
	}

	//通知列表
	public function get_notice_list() {
		$list=$this->model->table('gossip_news')->limit($this->jsonData['start_number'],$this->jsonData['end_number'])->select();
		foreach ($list as $key => $value) {
			$list[$key]['date']=$list[$key]['created'];
			unset($list[$key]['message']);
			unset($list[$key]['modified']);
			unset($list[$key]['user_id']);
			unset($list[$key]['created']);
		}
		$data['result']=true;
		$data['data']=$list;
		$this->respondSuccess($data,$_GET['_action']);
	}
}